package helper.scxml.strategy

import helper.base.math.DoubleMatrixHelper.DoubleMatrix.Companion.makeDoubleMatrix

object ZoneStrategyHelper {
    class DifferenceBoundsMatrix(
        val vars: ArrayList<String>,
    ) {
        val matrixSize = vars.size + 1
        val doubleMatrix = makeDoubleMatrix(
            matrixSize,
        )

        companion object {
            fun getDifferenceBoundsMatrix(
                vars: ArrayList<String>,
            ): DifferenceBoundsMatrix {
                return DifferenceBoundsMatrix(
                    vars,
                )
            }

            fun getDifferenceBoundsMatrix(
                matrixSize: Int,
            ): DifferenceBoundsMatrix {
                val vars = ArrayList<String>()
                for (i in 1 until matrixSize) {
                    vars.add("c${i}")
                }
                return getDifferenceBoundsMatrix(
                    vars,
                )
            }
        }

        private fun ifInZone(
            vs: ArrayList<Int>,
        ): Boolean {
            val hashSetOf = HashSet<Int>()
            hashSetOf.addAll(vs)
            require(hashSetOf.size > 0)
            require(hashSetOf.first() > 0)
            // TODO: 2023/07/06
            return false
        }

        fun ifInZone(
            c_i: Int,
            c_v: Int,
        ): Boolean {
            require(c_i > 0)
            val ijs = ArrayList<Pair<Int, Int>>()
            ijs.add(Pair(c_i, 0))
            for ((i, j) in ijs) {
                if (c_v.toDouble() !in doubleMatrix[j, i]..doubleMatrix[i, j]) {
                    return false
                }
            }
            return true
        }

        fun type1Touch(
            init: (Double, Int, Int, Double) -> Unit
        ) {
            for (i in 1 until doubleMatrix.rows) {
                for (j in 0 until i) {
                    init(doubleMatrix[j, i], i, j, doubleMatrix[i, j])
                }
            }
        }

        fun byIndexGetVar(i: Int): String {
            return vars[i - 1]
        }

        fun toStr(): String {
            val sb = StringBuilder()
            type1Touch { lowBound, i, j, highBound ->
                sb.append(
                    "${lowBound}<=" +
                            "${byIndexGetVar(i)}${if (j != 0) "-${byIndexGetVar(j)}" else ""}" +
                            "<=${highBound}\n"
                )
            }
            return sb.toString()
        }

        fun check(): Boolean {
            var res = true
            type1Touch { lowBound, i, j, highBound ->
                if (res && lowBound > highBound) {
                    res = false
                }
            }
            return res
        }
    }
}